package com.lizemin.spring;

import cn.hutool.core.util.StrUtil;
import com.lizemin.spring.annotation.Autowire;
import com.lizemin.spring.annotation.Value;
import com.lizemin.spring.util.YamlConfigLoader;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lzm
 * @date 2025/4/26 11:53
 * @description
 */
public class BeanFactory {

    /**
     * bean容器，缓存实例化后的bean对象
     */
    public static final ConcurrentHashMap<Class<?>, Object> beanMap = new ConcurrentHashMap<>();

    /**
     * beanClass，用于bean实例化
     */
    private final Set<Class<?>> beanClass;

    public BeanFactory(Set<Class<?>> beanClass) {
        this.beanClass = beanClass;
    }

    /**
     * 注册bean
     */
    public void registerBean() {
        for (Class<?> clazz : beanClass) {
            Object bean;
            try {
                bean = getBean(clazz);
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowire.class)) {
                        Class<?> fieldType = field.getType();
                        if (!beanClass.contains(fieldType)) {
                            throw new RuntimeException("无法注入" + fieldType + "类型的bean，请为其添加@component注解");
                        }
                        Object filedBean = getBean(fieldType);
                        field.setAccessible(true);
                        field.set(bean, filedBean);
                    }
                    if (field.isAnnotationPresent(Value.class)) {
                        Value value = field.getAnnotation(Value.class);
                        Object configValue = YamlConfigLoader.getConfig(value.value(), field.getType());
                        field.setAccessible(true);
                        field.set(bean, configValue);
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(StrUtil.format("class {}实例化失败", clazz.getName()));
            }

        }
    }

    /**
     * 根据类型获取bean
     *
     * @param clazz 类的class
     * @param <T> 泛型
     * @return bean实例
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> clazz) {
        Object bean = beanMap.get(clazz);
        if (Objects.nonNull(bean)) {
            return (T) bean;
        }
        // 如果没找到, 则实例化bean，并将bean放到缓存中
        try {
            T t = clazz.newInstance();
            beanMap.put(clazz, t);
            return t;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 拿到所有标记了特定注解的beanClass
     *
     * @param annotation 注解
     * @return 所有标记了特定注解的beanClass
     */
    public static Set<Class<?>> getBeanClassWithAnnotation(Class<? extends Annotation> annotation) {
        HashSet<Class<?>> clazzs = new HashSet<>();
        for (Class<?> clazz : beanMap.keySet()) {
            if (clazz.isAnnotationPresent(annotation)) {
                clazzs.add(clazz);
            }
        }
        return clazzs;
    }

}
